package net.tv90.bfmccore.slot;

import net.tv90.bfmccore.helper.FlanHelper;
import net.tv90.bfmccore.helper.InventoryHelper;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static net.tv90.bfmccore.BFMCCore.PLUGIN_ROOT;
import static net.tv90.bfmccore.util.file.FileUtils.writeAllText;
import static net.tv90.bfmccore.helper.FactionHelper.getFaction2;
import static net.tv90.bfmccore.helper.ItemHelper.stringToMaterial;

public class SlotHelper {
    //储存默认装备
    public static HashMap<Object, Object> DefaultSlotData = new HashMap<>();

    public static void saveWeapon(Player p, String type, String gun, String ammo, int amount) throws Exception {

        //获取玩家的全部Slot序列化Map
        //K = 阵营  V = Slot序列化Map
        HashMap<Object, Object> allSlot = getAllSlotMap(p);

        //System.out.println(allSlot);

        //获取玩家的阵营
        String faction = getFaction2(p);

        //根据玩家阵营获取玩家当前阵营和兵种的Slot序列化Map
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);

        //System.out.println(factionSlotMap);

        if (Objects.equals(type, "MainWeapon")) {

            //根据函数形参创建新的MainWeapon
            HashMap<String, String> attachment = new HashMap<>();
            MainWeapon weapon = new MainWeapon(gun, ammo, amount, attachment);
            weapon.setMainWeapon(gun, ammo, amount);

            //把Map反序列化为Slot
            Slot slot = new Slot(factionSlotMap);

            //System.out.println(slot.toString());
            //System.out.println(slot.SlotToHashMap());
            //System.out.println(slot.MainWeaponToHashMap());
            //System.out.println(slot.SideArmsToHashMap());

            //将新的MainWeapon存储进Slot
            slot.setMainWeaponSlot(weapon);

            //System.out.println(slot.toString());
            //System.out.println(slot.SlotToHashMap());
            //System.out.println(slot.MainWeaponToHashMap());
            //System.out.println(slot.SideArmsToHashMap());

            //把Slot序列化并且存储
            allSlot.put(faction, slot.SlotToHashMap());

            //System.out.println(allSlot);

            File file = generateFile(p);
            if (!file.exists()) file.delete();
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        } else if (Objects.equals(type, "SideArms")) {
            HashMap<String, String> attachment = new HashMap<>();
            SideArms weapon = new SideArms(gun, ammo, amount, attachment);
            weapon.setSideArms(gun, ammo, amount);
            Slot slot = new Slot(factionSlotMap);
            slot.setSideArmsSlot(weapon);
            allSlot.put(faction, slot.SlotToHashMap());
            File file = generateFile(p);
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        }
    }

    public static void saveAmmo(Player p, String type, String ammo, int amount) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        if (Objects.equals(type, "MainWeapon")) {
            Slot slot = new Slot(factionSlotMap);
            slot.setMainWeaponAmmoSlot(ammo, amount);
            allSlot.put(faction, slot.SlotToHashMap());
            File file = generateFile(p);
            if (!file.exists()) file.delete();
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        } else if (Objects.equals(type, "SideArms")) {
            Slot slot = new Slot(factionSlotMap);
            slot.setSideArmsAmmoSlot(ammo, amount);
            allSlot.put(faction, slot.SlotToHashMap());
            File file = generateFile(p);
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        }
    }

    public static void saveAmmoType(Player p, String type, String ammoType) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        if (Objects.equals(type, "MainWeapon")) {
            Slot slot = new Slot(factionSlotMap);
            slot.setMainWeaponAmmoTypeSlot(ammoType);
            allSlot.put(faction, slot.SlotToHashMap());
            File file = generateFile(p);
            if (!file.exists()) file.delete();
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        } else if (Objects.equals(type, "SideArms")) {
            Slot slot = new Slot(factionSlotMap);
            slot.setSideArmsAmmoTypeSlot(ammoType);
            allSlot.put(faction, slot.SlotToHashMap());
            File file = generateFile(p);
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        }
    }


    public static void saveOther(Player p, String type, String item) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        if (Objects.equals(type, "MeleeWeapon")) {
            Slot slot = new Slot(factionSlotMap);
            slot.setMeleeWeaponSlot(item);
            allSlot.put(faction, slot.SlotToHashMap());
            File file = generateFile(p);
            if (!file.exists()) file.delete();
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        } else if (Objects.equals(type, "Cloth")) {
            Slot slot = new Slot(factionSlotMap);
            slot.setClothSlot(item);
            allSlot.put(faction, slot.SlotToHashMap());
            File file = generateFile(p);
            writeAllText(file, (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        }
    }

    public static void saveGrenade(Player p, String grenade, int num) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        Slot slot = new Slot(factionSlotMap);
        Grenade gl = new Grenade(grenade, num);
        gl.setGrenade(grenade, num);
        slot.setGrenadeSlot(gl);
        allSlot.put(faction, slot.SlotToHashMap());
        writeAllText(generateFile(p), (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
    }

    public static void saveGadgets(Player p, String gadgets, int num, int index) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        Slot slot = new Slot(factionSlotMap);

        HashMap<Integer, Integer> map1 = new HashMap<>();
        map1.put(num, index);
        HashMap<String, HashMap<Integer, Integer>> map2 = new HashMap<>();
        map2.put(gadgets, map1);
        if (slot.getGadgetsSlot() == null) {
            slot.setGadgetsSlot(map2);
        } else slot.getGadgetsSlot().put(gadgets, map1);

        allSlot.put(faction, slot.SlotToHashMap());
        writeAllText(generateFile(p), (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
    }

    public static void clearGadgets(Player p) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        Slot slot = new Slot(factionSlotMap);
        slot.setGadgetsSlot(null);
        allSlot.put(faction, slot.SlotToHashMap());
        writeAllText(generateFile(p), (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
    }

    public static void clearGadgets2(Player p) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        Slot slot = new Slot(factionSlotMap);
        slot.setGadgets2Slot(null);
        allSlot.put(faction, slot.SlotToHashMap());
        writeAllText(generateFile(p), (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
    }

    public static void saveGadgets2(Player p, String gadgets, int num, int index) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        Slot slot = new Slot(factionSlotMap);

        HashMap<Integer, Integer> map1 = new HashMap<>();
        map1.put(num, index);
        HashMap<String, HashMap<Integer, Integer>> map2 = new HashMap<>();
        map2.put(gadgets, map1);
        if (slot.getGadgets2Slot() == null) {
            slot.setGadgets2Slot(map2);
        } else slot.getGadgets2Slot().put(gadgets, map1);

        allSlot.put(faction, slot.SlotToHashMap());
        writeAllText(generateFile(p), (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
    }

    public static void saveAttachments(Player p, String weapon, String type, String att) throws Exception {
        HashMap<Object, Object> allSlot = getAllSlotMap(p);
        String faction = getFaction2(p);
        HashMap<Object, Object> factionSlotMap = (HashMap<Object, Object>) allSlot.get(faction);
        if (Objects.equals(weapon, "MainWeapon")) {
            MainWeapon mainWeapon = getMainWeapon(p);

            if (mainWeapon.MainWeaponAttachment == null) {
                HashMap<String, String> attachment = new HashMap<>();
                attachment.put(type, att);
                mainWeapon.MainWeaponAttachment = attachment;
            } else mainWeapon.MainWeaponAttachment.put(type, att);

            Slot slot = new Slot(factionSlotMap);
            slot.setMainWeaponSlot(mainWeapon);
            allSlot.put(faction, slot.SlotToHashMap());
            writeAllText(generateFile(p), (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));

        } else if (Objects.equals(weapon, "SideArms")) {
            SideArms sideArms = getSideArms(p);

            if (sideArms.SideArmsAttachment == null) {
                HashMap<String, String> attachment = new HashMap<>();
                attachment.put(type, att);
                sideArms.SideArmsAttachment = attachment;
            } else sideArms.SideArmsAttachment.put(type, att);

            Slot slot = new Slot(factionSlotMap);
            slot.setSideArmsSlot(sideArms);
            allSlot.put(faction, slot.SlotToHashMap());
            writeAllText(generateFile(p), (new Yaml()).dumpAs(allSlot, Tag.MAP, DumperOptions.FlowStyle.BLOCK));
        }
    }

    /**
     * 给玩家装备
     * @param p 玩家
     */
    public static void giveSlot(Player p) throws Exception {
        //if(getCountry(p) == null || getCountry(p).equals("NoFaction")) return;
        Inventory inv = p.getInventory();
        Slot slot = getSlot(p);
        System.out.println(slot);
        String cloth = slot.cloth;
        ItemStack meleeIsk = new ItemStack(stringToMaterial(slot.meleeWeapon), 1);
        ItemStack mainWeaponIsk = new ItemStack(stringToMaterial(slot.mainWeapon.MainWeapon), 1);
        ItemStack sideArmsIsk = new ItemStack(stringToMaterial(slot.sidearms.SideArms), 1);
        ItemStack grenadeIsk = new ItemStack(stringToMaterial(slot.grenade.Grenade), slot.grenade.GrenadeCount);
        ItemStack mainWeaponAmmoIsk = new ItemStack(stringToMaterial(slot.mainWeapon.MainWeaponAmmo), slot.mainWeapon.MainWeaponAmmoCount);
        ItemStack sideArmsAmmoIsk = new ItemStack(stringToMaterial(slot.sidearms.SideArmsAmmo), slot.sidearms.SideArmsAmmoCount);
        HashMap<String, String> mainAtt = slot.mainWeapon.MainWeaponAttachment;
        HashMap<String, String> sideArmAtt = slot.sidearms.SideArmsAttachment;
        HashMap<String, HashMap<Integer, Integer>> gadgets = slot.gadgets;
        HashMap<String, HashMap<Integer, Integer>> gadgets2 = slot.gadgets2;

        //装备主武器配件
        if (mainAtt != null) {
            for (Map.Entry<String, String> entry : mainAtt.entrySet()) {
                mainWeaponIsk = FlanHelper.setAttachment(mainWeaponIsk, entry.getKey().toLowerCase(), stringToMaterial(entry.getValue()));
            }
        }
        //装备副武器配件
        if (sideArmAtt != null) {
            for (Map.Entry<String, String> entry : sideArmAtt.entrySet()) {
                sideArmsIsk = FlanHelper.setAttachment(sideArmsIsk, entry.getKey().toLowerCase(), stringToMaterial(entry.getValue()));
            }
        }

        //装填弹药
        if(!Objects.equals(slot.mainWeapon.MainWeaponAmmo, "AIR")){
            mainWeaponIsk = FlanHelper.setAmmo(mainWeaponIsk, stringToMaterial(slot.mainWeapon.MainWeaponAmmo),15);
        }
        if(!Objects.equals(slot.sidearms.SideArmsAmmo, "AIR")){
            sideArmsIsk = FlanHelper.setAmmo(sideArmsIsk, stringToMaterial(slot.sidearms.SideArmsAmmo),15);
        }

        if (!p.isOp()) {
            try {
                p.setOp(true);
                p.performCommand("minecraft:clear");
                p.performCommand("kit " + cloth);
            } finally {
                p.setOp(false);
            }
        } else {
            p.performCommand("minecraft:clear");
            p.performCommand("kit " + cloth);
        }

        inv.setItem(0, meleeIsk);
        inv.setItem(1, mainWeaponIsk);
        inv.setItem(2, sideArmsIsk);
        inv.setItem(3, grenadeIsk);
        inv.setItem(19, mainWeaponAmmoIsk);
        inv.setItem(20, sideArmsAmmoIsk);

        if (gadgets != null) {
            for (Map.Entry<String, HashMap<Integer, Integer>> entry : gadgets.entrySet()) {
                InventoryHelper.addItemIndex(
                        inv,
                        stringToMaterial(entry.getKey()),
                        entry.getValue().keySet().iterator().next(),
                        entry.getValue().values().iterator().next()
                );
            }
        }

        if (gadgets2 != null) {
            for (Map.Entry<String, HashMap<Integer, Integer>> entry : gadgets2.entrySet()) {
                InventoryHelper.addItemIndex(
                        inv,
                        stringToMaterial(entry.getKey()),
                        entry.getValue().keySet().iterator().next(),
                        entry.getValue().values().iterator().next()
                );
            }
        }
    }

    public static void giveSlot(Player p,Slot slot) {
        //if(getCountry(p) == null || getCountry(p).equals("NoFaction")) return;
        Inventory inv = p.getInventory();
        inv.clear();
        ItemStack meleeIsk = new ItemStack(stringToMaterial(slot.meleeWeapon), 1);
        ItemStack mainWeaponIsk = new ItemStack(stringToMaterial(slot.mainWeapon.MainWeapon), 1);
        ItemStack sideArmsIsk = new ItemStack(stringToMaterial(slot.sidearms.SideArms), 1);
        ItemStack grenadeIsk = new ItemStack(stringToMaterial(slot.grenade.Grenade), slot.grenade.GrenadeCount);
        ItemStack mainWeaponAmmoIsk = new ItemStack(stringToMaterial(slot.mainWeapon.MainWeaponAmmo), slot.mainWeapon.MainWeaponAmmoCount);
        ItemStack sideArmsAmmoIsk = new ItemStack(stringToMaterial(slot.sidearms.SideArmsAmmo), slot.sidearms.SideArmsAmmoCount);
        HashMap<String, String> mainAtt = slot.mainWeapon.MainWeaponAttachment;
        HashMap<String, String> sideArmAtt = slot.sidearms.SideArmsAttachment;
        HashMap<String, HashMap<Integer, Integer>> gadgets = slot.gadgets;
        HashMap<String, HashMap<Integer, Integer>> gadgets2 = slot.gadgets2;

        //装备主武器配件
        if (mainAtt != null) {
            for (Map.Entry<String, String> entry : mainAtt.entrySet()) {
                mainWeaponIsk = FlanHelper.setAttachment(mainWeaponIsk, entry.getKey().toLowerCase(), stringToMaterial(entry.getValue()));
            }
        }
        //装备副武器配件
        if (sideArmAtt != null) {
            for (Map.Entry<String, String> entry : sideArmAtt.entrySet()) {
                sideArmsIsk = FlanHelper.setAttachment(sideArmsIsk, entry.getKey().toLowerCase(), stringToMaterial(entry.getValue()));
            }
        }

        //装填弹药
        if(!Objects.equals(slot.mainWeapon.MainWeaponAmmo, "AIR")){
            mainWeaponIsk = FlanHelper.setAmmo(mainWeaponIsk, stringToMaterial(slot.mainWeapon.MainWeaponAmmo),15);
        }
        if(!Objects.equals(slot.sidearms.SideArmsAmmo, "AIR")){
            sideArmsIsk = FlanHelper.setAmmo(sideArmsIsk, stringToMaterial(slot.sidearms.SideArmsAmmo),15);
        }

        if(slot.cloth != null){
            String cloth = slot.cloth;
            if (!p.isOp()) {
                try {
                    p.setOp(true);
                    p.performCommand("minecraft:clear");
                    p.performCommand("kit " + cloth);
                } finally {
                    p.setOp(false);
                }
            } else {
                p.performCommand("minecraft:clear");
                p.performCommand("kit " + cloth);
            }
        }

        inv.setItem(0, meleeIsk);
        inv.setItem(1, mainWeaponIsk);
        inv.setItem(2, sideArmsIsk);
        inv.setItem(3, grenadeIsk);
        inv.setItem(19, mainWeaponAmmoIsk);
        inv.setItem(20, sideArmsAmmoIsk);

        if (gadgets != null) {
            for (Map.Entry<String, HashMap<Integer, Integer>> entry : gadgets.entrySet()) {
                InventoryHelper.addItemIndex(
                        inv,
                        stringToMaterial(entry.getKey()),
                        entry.getValue().keySet().iterator().next(),
                        entry.getValue().values().iterator().next()
                );
            }
        }

        if (gadgets2 != null) {
            for (Map.Entry<String, HashMap<Integer, Integer>> entry : gadgets2.entrySet()) {
                InventoryHelper.addItemIndex(
                        inv,
                        stringToMaterial(entry.getKey()),
                        entry.getValue().keySet().iterator().next(),
                        entry.getValue().values().iterator().next()
                );
            }
        }
    }

    //从文件中获取玩家所有Slot的序列化Map
    //如果玩家文件不存在或内容不全，就读取默认装备文件
    public static HashMap<Object, Object> getAllSlotMap(Player p) throws IOException {
        File file = generateFile(p);
        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
            HashMap<Object, Object> slotMap = (HashMap<Object, Object>) new Yaml().loadAs(inputStream, HashMap.class);
            if (slotMap == null || slotMap.isEmpty()) {
                return new HashMap<>(DefaultSlotData);
            }
            return slotMap;
        } catch (Exception e) {
            return new HashMap<>(DefaultSlotData);
        }
    }


    //从文件中根据玩家的阵营和兵种获取对应的Slot
    public static Slot getSlot(Player p) throws Exception {
        HashMap<Object, Object> factionMap = (HashMap<Object, Object>) getAllSlotMap(p).get(getFaction2(p));
        return new Slot(factionMap);
    }

    //从文件中根据玩家的阵营和兵种获取对应的MainWeapon
    public static MainWeapon getMainWeapon(Player p) throws Exception {
        Slot slot = getSlot(p);
        return slot.mainWeapon;
    }

    //从文件中根据玩家的阵营和兵种获取对应的SideArms
    public static SideArms getSideArms(Player p) throws Exception {
        Slot slot = getSlot(p);
        return slot.sidearms;
    }

    //生成"BFMCCore/slot/玩家id.yml"文件存储玩家Slot信息
    public static File generateFile(Player p) {
        if (!PLUGIN_ROOT.exists()) PLUGIN_ROOT.mkdir();
        File dataDirectory = new File(PLUGIN_ROOT, "slot");
        if (!dataDirectory.exists()) dataDirectory.mkdir();
        File file = new File(dataDirectory, p.getName() + ".yml");
        if (!file.exists()) file.delete();
        return file;
    }

    //获取默认的阵营装备并存储
    public static HashMap<Object, Object> getDefaultSlotMap() throws IOException {
        if (!PLUGIN_ROOT.exists()) {
            PLUGIN_ROOT.mkdir();
        }
        File dataDirectory = new File(PLUGIN_ROOT, "default");
        if (!dataDirectory.exists()) {
            dataDirectory.mkdir();
        }
        File file = new File(dataDirectory, "DefaultSlot.yml");
        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
            return (HashMap<Object, Object>) new Yaml().loadAs(inputStream, HashMap.class);
        }
    }


}
